﻿#include <windows.h>
#include "game.h"
#include <time.h>

CGame::CGame(int cmdShow)
{
	this->cmdShow = cmdShow;
}

void CGame::GameInit()
{
	_InitWindow(cmdShow);
	_InitDirectX();
	_InitInput();
	LoadResources(G_Device);
}

void CGame::GameRun()
{
	MSG msg; 
	ZeroMemory(&msg, sizeof(msg));

	DWORD frame_start = GetTickCount();
	DWORD tick_per_frame = 100 / G_FrameRate;

	//Vòng lặp chính quản lý thông điệp
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		
		DWORD now = GetTickCount();
		_DeltaTime = now - frame_start;

		if(_DeltaTime >= tick_per_frame)
		{
			//Vẽ các thành phần con
			_RenderFrame();
			frame_start = now;
		}

		GameUpdate(_DeltaTime);

		//Input điều khiển
		_ProcessKeyboard();
		ProcessInput(G_Device, _DeltaTime);
	}
}

void CGame::GameEnd()
{
	if (G_Device!=NULL) G_Device->Release();
	if (G_DirectX!=NULL) G_DirectX->Release();
}

bool CGame::_InitWindow(int cmdShow)
{
	WNDCLASSEX wcex;
	
	wcex.cbClsExtra = 0;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.cbWndExtra = 0;

	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //Thiết lập kiểu con trỏ chuột mặc định
	wcex.hIcon = NULL;
	wcex.hIconSm = NULL;
	wcex.hInstance = G_hInstance;
	
	wcex.lpfnWndProc = (WNDPROC) CGame::_WinProc;
	wcex.lpszClassName = G_GameName;
	wcex.lpszMenuName = NULL;
	wcex.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClassEx(&wcex);

	//Xét toàn màn hình
	DWORD ScreenStyle;
	if(G_IsFullScreen)
	{
		ScreenStyle = WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP; //toàn màn
	}
	else 
	{
		ScreenStyle = WS_OVERLAPPEDWINDOW; //cửa sổ
	}

	//Khởi tạo cửa sổ
	G_hWnd = 
		CreateWindow(
		G_GameName,
		G_GameName,
		ScreenStyle,
		CW_USEDEFAULT, //Mặc định tọa độ X cửa sổ khi xuất hiện
		CW_USEDEFAULT, //Mặc định tọa độ Y cửa sổ khi xuất hiện
		G_ScreenWidth,
		G_ScreenHeight,
		NULL,
		NULL,
		G_hInstance,
		NULL);

	if(!G_hWnd)
	{
		GLMessage(L"Init hWnd Fail");
		return false;
	}

	if(!G_hInstance)
	{
		GLMessage(L"Init hInstance fail");

	}

	ShowWindow(G_hWnd, cmdShow);
	UpdateWindow(G_hWnd);

	return true;
}

bool CGame::_InitDirectX()
{
	G_DirectX = Direct3DCreate9(D3D_SDK_VERSION);
	D3DPRESENT_PARAMETERS d3dpp;

	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
	
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferFormat = G_BackBufferFormat;
	d3dpp.BackBufferHeight = G_ScreenHeight;
	d3dpp.BackBufferWidth = G_ScreenWidth;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed = !G_IsFullScreen;
	d3dpp.hDeviceWindow = G_hWnd;

	G_DirectX->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_REF,
		G_hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&G_Device);

	if(G_Device == NULL)
	{
		return false;
	}

	srand(time(NULL));

	//
	G_Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &G_BackBuffer);
	
	//Khởi tạo sprite handler
	D3DXCreateSprite(G_Device, &G_SpriteHandler);

	return true;
}

bool CGame::_InitInput()
{
	HRESULT hrs;

	//Khởi tạo đối tượng input
	hrs = DirectInput8Create(
		G_hInstance,
		DIRECTINPUT_VERSION,
		IID_IDirectInput8,
		(VOID **)&G_DirectInput,
		NULL);

	if(hrs != D3D_OK)
	{
		GLMessage(L"Init Input Fail");
		return false;
	}

	//Khởi tạo thiết bị input là bàn phím
	hrs = G_DirectInput->CreateDevice(GUID_SysKeyboard, &G_KeyBoard, NULL);

	hrs = G_KeyBoard->SetDataFormat(&c_dfDIKeyboard);
	hrs = G_KeyBoard->SetCooperativeLevel(G_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	
	//Buffer input
	DIPROPDWORD dipdw;
	
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwHow = DIPH_DEVICE;
	dipdw.diph.dwObj = 0;
	dipdw.diph.dwSize = sizeof(DIPROPDWORD);
	dipdw.dwData = GL_KEY_BUFFER_SIZE;

	hrs = G_KeyBoard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
	hrs = G_KeyBoard->Acquire();

	if(hrs != D3D_OK)
	{
		return false;
	}
	
	return true;
}

void CGame::_ProcessKeyboard()
{
	//Quản lý các phím được tác động
	G_KeyBoard->GetDeviceState(sizeof(_KeyStates), _KeyStates);

	//Thoát khi nhấn phím escape
	if(_IsKeyDown(DIK_ESCAPE))
	{
		PostMessage(G_hWnd, WM_QUIT, 0, 0);
	}

	//Lấy tất cả các phím được thực hiện
	DWORD dwElements = GL_KEY_BUFFER_SIZE;
	HRESULT hrs = G_KeyBoard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), _KeyEvents, &dwElements, 0);

	//Duyệt tất cả các phím 
	for(DWORD i = 0; i < dwElements; i++)
	{
		int KeyCode = _KeyEvents[i].dwOfs;
		int KeyState = _KeyEvents[i].dwData;
		
		if((KeyState & 0x80) > 0)
		{
			OnKeyDown(KeyCode);
		}
		else 
		{
			OnKeyUp(KeyCode);
		}
	}
}

int CGame::_IsKeyDown(int KeyCode)
{
	return (_KeyStates[KeyCode] & 0x80) > 0;
}

LRESULT CALLBACK CGame::_WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

void CGame::_RenderFrame()
{
	if (G_Device->BeginScene()) 
	{
		RenderFrame(G_Device, _DeltaTime);
		G_Device->EndScene();
	}

	G_Device->Present(NULL,NULL,NULL,NULL);
}

void CGame::RenderFrame(LPDIRECT3DDEVICE9 d3ddv, int Delta) 
{
	d3ddv->ColorFill(G_BackBuffer,NULL,D3DCOLOR_XRGB(0,0,0));
}

void CGame::LoadResources(LPDIRECT3DDEVICE9 d3dDevice) { }

void CGame::ProcessInput(LPDIRECT3DDEVICE9 d3dDevice, int Delta) { }

void CGame::OnKeyDown(int KeyCode) { }

void CGame::OnKeyUp(int KeyCode) { }

void CGame::GameUpdate(int deltaTime) { }